package cn.fufeiii.bt.common.util;

import com.fasterxml.jackson.databind.json.JsonMapper;
import okhttp3.*;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Objects;
import java.util.StringJoiner;

/**
 * @author FuFei
 */
public class OkHttp3Util {
    private static final OkHttpClient OK_HTTP_CLIENT;
    private static final MediaType MEDIA_TYPE_JSON;
    private static final JsonMapper JSON_MAPPER;

    static {
        OK_HTTP_CLIENT = new OkHttpClient().newBuilder().build();
        MEDIA_TYPE_JSON = MediaType.get("application/json");
        JSON_MAPPER = JsonUtil.newMapper();
    }

    /**
     * 获取Request
     */
    private static Request getRequest(String url, String method, byte[] requestBody, Map<String, String> headerMap) {
        // Builder默认是GET请求
        Request.Builder builder = new Request.Builder();
        builder.url(url);
        if (Objects.nonNull(requestBody)) {
            builder.method(method, RequestBody.create(requestBody, MEDIA_TYPE_JSON));
        }
        if (Objects.nonNull(headerMap) && !headerMap.isEmpty()) {
            builder.headers(Headers.of(headerMap));
        }
        return builder.build();
    }

    /**
     * 解析响应体
     */
    @SuppressWarnings("unchecked")
    private static <T> T readResponse(ResponseBody responseBody, Class<T> clazz) throws IOException {
        if (Objects.isNull(responseBody)) {
            return null;
        }
        // 如果是string直接返回，否则按照json解析
        if (String.class.getTypeName().equals(clazz.getTypeName())) {
            return (T) responseBody.string();
        }
        return JSON_MAPPER.readValue(responseBody.bytes(), clazz);
    }

    /**
     * 获取查询参数
     */
    private static String getQueryParam(boolean isAppend, Map<String, String> queryParamMap) {
        if (Objects.isNull(queryParamMap)) {
            return "";
        }
        StringJoiner joiner = new StringJoiner("&");
        for (String key : queryParamMap.keySet()) {
            joiner.add(URLEncoder.encode(key, StandardCharsets.UTF_8) + "="
                    + URLEncoder.encode(queryParamMap.getOrDefault(key, ""), StandardCharsets.UTF_8));
        }
        String queryParamStr = joiner.toString();
        return isAppend ? "&" + queryParamStr : "?" + queryParamStr;
    }


    /**
     * GET
     */
    public static String get(String url) {
        return get(url, null);
    }

    /**
     * POST
     */
    public static String get(String url, Map<String, String> headerMap) {
        return get(url, headerMap, String.class);
    }

    /**
     * GET
     */
    public static <T> T get(String url, Map<String, String> headerMap, Class<T> clazz) {
        return submit(url, "GET", null, headerMap, clazz);
    }

    /**
     * POST
     */
    public static String post(String url, String json) {
        return post(url, json, null, String.class);
    }

    /**
     * POST
     */
    public static <T> T post(String url, String json, Class<T> clazz) {
        return post(url, json, null, clazz);
    }

    /**
     * POST
     */
    public static String post(String url, String json, Map<String, String> headerMap) {
        return post(url, json, headerMap, String.class);
    }

    /**
     * POST
     */
    public static <T> T post(String url, String json, Map<String, String> headerMap, Class<T> clazz) {
        return submit(url, "POST", json.getBytes(StandardCharsets.UTF_8), headerMap, clazz);
    }


    /**
     * SUBMIT
     */
    public static <T> T submit(String url, String method, byte[] requestBody, Map<String, String> headerMap, Class<T> clazz) {
        Request request = getRequest(url, method, requestBody, headerMap);
        try (Response response = OK_HTTP_CLIENT.newCall(request).execute()) {
            return readResponse(response.body(), clazz);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
